package org.gpp.proj1.particle;

import java.util.HashMap;
import java.util.Map;

import com.jme.image.Texture;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jmex.effects.ParticleManager;

/**
 * Factory de part�culas que cria part�culas de v�rios tipos
 * sob demanda dos clientes.
 * @author Gustavo de Farias
 */
public class ParticleFactory {
	
	/**
	 * A �nica inst�ncia da factory.
	 */
	private static ParticleFactory factory;
	
	private Map<String, ParticleManager> managers;
	
	/**
	 * Construtor privado.
	 */
	private ParticleFactory() {
		
		this.managers = new HashMap<String, ParticleManager>();
	}
	
	/**
	 * Obt�m a �nica inst�ncia da factory.
	 * @return A �nica inst�ncia da factory.
	 */
	public static ParticleFactory getInstance() {
		
		if (factory == null) {
			
			factory = new ParticleFactory();
		}
		
		return factory;
	}

	/**
	 * Cria uma part�cula (um TriMesh) de um determinado tipo.
	 * @param type Uma String contendo o tipo da part�cula. O "tipo"
	 * � normalmente o nome de um arquivo de descri��o de part�culas
	 * previamente criado e que consta nos resources do programa.
	 * @return Um gerenciador de part�culas de onde pode ser facilmente
	 * obtida a part�cula de interesse.
	 */
	public ParticleManager createParticle(String type) {
		
		if (this.managers.containsKey(type)) {
			return this.managers.get(type);
		}
		
		// Cria um parser.
		// Usa o tipo da part�cula como nome do arquivo descritor a ser lido.
		ParticleFileParser parser = new ParticleFileParser("./res/particle/" + type + ".par");

		// Cria o gerenciador a ser retornado.
		ParticleManager manager = new ParticleManager(parser.getParticleNumber());
		// Seta a maioria das propriedades vindas do descritor.
		parser.fillAttributes(manager);
		manager.getParticles().addController(manager);
		
		// Cria e seta o Alpha State
		AlphaState as = DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();
		as.setBlendEnabled(true);
		as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
		as.setDstFunction(AlphaState.DB_ONE);
		as.setTestEnabled(true);
		as.setTestFunction(AlphaState.TF_GREATER);
		as.setEnabled(true);
		manager.getParticles().setRenderState(as);

		// Cria e seta o Texture State
		TextureState ts = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
		ts.setTexture(TextureManager.loadTexture(parser.getTexture(), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR));
		ts.setEnabled(true);
		manager.getParticles().setRenderState(ts);

		// Cria e seta o Z Buffer State
		ZBufferState zbuf = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
		zbuf.setWritable(false);
		zbuf.setEnabled(true);
		zbuf.setFunction(ZBufferState.CF_LEQUAL);
		manager.getParticles().setRenderState(zbuf);

		manager.getParticles().setLocalScale( parser.getScale() );
		
		manager.getParticles().updateGeometricState( 0.0f, true );
		manager.getParticles().updateRenderState();
		
		this.managers.put(type, manager);
		
		return manager;
	}
	
}
